﻿/**************************************************************
 *
 * 唯一标识：a8b150df-50dd-4f90-b9ad-3d151aba847d
 * 命名空间：Sgr.Utilities
 * 创建时间：2023/7/24 11:59:59
 * 机器名称：DESKTOP-S0D075D
 * 创建者：antho
 * 电子邮箱：fengqinhua2016@163.com
 * 描述：
 *
 **************************************************************/

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Sgr.Utilities
{
    /// <summary>
    /// 本地文件帮助类
    /// </summary>
    public static class LocalFileHelper
    {
        /// <summary>
        /// 获取当前应用程序所在目录
        /// </summary>
        /// <returns></returns>
        public static string GetApplicationDirectory()
        {
            return AppContext.BaseDirectory;
        }

        /// <summary>
        /// 获取当前用户工作目录
        /// </summary>
        /// <param name="appName"></param>
        /// <returns></returns>
        public static string GetCurrentUserDataDirectory(string appName = "sgr")
        {
            string? configDir = "";

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                //如果是Linux系统，首先为环境变量 XDG_DATA_HOME 对应的目录；其次为环境变量 HOME 对应的目录
                configDir = System.Environment.GetEnvironmentVariable("XDG_DATA_HOME", EnvironmentVariableTarget.Machine);
                if (!string.IsNullOrEmpty(configDir))
                    configDir = System.IO.Path.Combine(configDir, appName);
                else
                {
                    configDir = EnvironmentHelper.GetEnvironmentVariable("HOME");
                    if (!string.IsNullOrEmpty(configDir))
                        configDir = System.IO.Path.Combine(configDir, ".local", "share", appName);
                }
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                ////如果是Winodws系统,为环境变量 LocalAppData AppData 对应的目录 AppData\Roaming
                //configDir = System.Environment.GetEnvironmentVariable("LocalAppData");

                configDir = System.Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
                if (!string.IsNullOrEmpty(configDir))
                    configDir = System.IO.Path.Combine(configDir, appName);
            }

            //如果实在找不到则返回当前应用程序目录
            if (string.IsNullOrEmpty(configDir))
            {
                configDir = GetApplicationDirectory();
                if (!string.IsNullOrEmpty(configDir))
                    configDir = System.IO.Path.Combine(configDir, "workdir", "current_userdata");
            }

            //检查文件夹是否存在，如果不存在则创建之
            if (!string.IsNullOrEmpty(configDir))
            {
                if (!System.IO.Directory.Exists(configDir))
                    System.IO.Directory.CreateDirectory(configDir);
            }

            return configDir;
        }

        /// <summary>
        ///  获取所有用户的共享工作目录
        /// </summary>
        /// <param name="appName"></param>
        /// <returns></returns>
        public static string GetAllUserDataDirectory(string appName = "sgr")
        {
            string configDir = "";

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                configDir = System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
                if (!string.IsNullOrEmpty(configDir))
                    configDir = System.IO.Path.Combine(configDir, appName);
            }

            //如果实在找不到则返回当前应用程序目录
            if (string.IsNullOrEmpty(configDir))
            {
                configDir = GetApplicationDirectory();
                if (!string.IsNullOrEmpty(configDir))
                    configDir = System.IO.Path.Combine(configDir, "workdir", "all_userdata");
            }

            //检查文件夹是否存在，如果不存在则创建之
            if (!string.IsNullOrEmpty(configDir))
            {
                if (!System.IO.Directory.Exists(configDir))
                    System.IO.Directory.CreateDirectory(configDir);
            }

            return configDir;
        }

        /// <summary>
        /// 如果文件夹不存在则创建
        /// </summary>
        /// <param name="directory"></param>
        public static void CreateDirectoryIfNotExists(string directory)
        {
            if (!Directory.Exists(directory))
                Directory.CreateDirectory(directory);
        }

        /// <summary>
        /// 如果文件夹存在则删除
        /// </summary>
        /// <param name="directory"></param>
        /// <param name="recursive"></param>
        public static void DeleteDirectoryIfExists(string directory, bool recursive)
        {
            if (Directory.Exists(directory))
                Directory.Delete(directory, recursive);
        }

        /// <summary>
        /// 读取指定文件，返回文件中的文本内容
        /// </summary>
        /// <param name="path"></param>
        /// <param name="encoding"></param>
        /// <returns></returns>
        public static async Task<string?> ReadFileContentToStringAsync(string path, Encoding? encoding = null)
        {
            var bytes = await ReadFileContentToBytesAsync(path);

            return StringHelper.ConvertFromBytesWithoutBom(bytes, encoding);
        }

        /// <summary>
        /// 读取指定文件，返回文件中的字节数组
        /// </summary>
        /// <param name="path"></param>
        /// <param name="maxLengthBytes">默认约50MB</param>
        /// <returns></returns>
        public static async Task<byte[]> ReadFileContentToBytesAsync(string path, long maxLengthBytes = 50L * 1024 * 1024)
        {
            Check.NotNull(path, nameof(path));

            if (maxLengthBytes <= 0)
                throw new ArgumentOutOfRangeException(nameof(maxLengthBytes), "最大长度必须大于 0。");

            var fi = new FileInfo(path);
            if (!fi.Exists)
                throw new FileNotFoundException($"无法找到文件: {path}", path);

            long length = fi.Length;
            if (length == 0)
                return Array.Empty<byte>();

            if (length > maxLengthBytes)
                throw new InvalidOperationException($"文件大小超出允许的最大值: {length} 字节，最大允许: {maxLengthBytes} 字节。");

            if (length > int.MaxValue)
                throw new NotSupportedException("文件过大，无法一次性读取到单个字节数组中。");

            // 使用标准库方法读取，简洁且由框架优化异步 IO
            return await File.ReadAllBytesAsync(path);
        }

        /// <summary>
        /// 将字符串内容写入指定的文件
        /// </summary>
        /// <param name="path">文件完整路径</param>
        /// <param name="content">要写入的内容</param>
        /// <param name="overwrite">是否覆盖现有文件，默认为 true</param>
        /// <param name="encoding">文件编码，默认为 UTF-8</param>
        /// <exception cref="ArgumentNullException">path 或 content 为 null 时抛出</exception>
        /// <exception cref="ArgumentException">path 为空字符串或仅包含空白字符时抛出</exception>
        /// <exception cref="PathTooLongException">指定的路径超过了系统定义的最大长度</exception>
        /// <exception cref="DirectoryNotFoundException">指定的路径无效</exception>
        /// <exception cref="IOException">写入文件时发生 IO 错误</exception>
        /// <exception cref="UnauthorizedAccessException">没有写入文件的权限</exception>
        public static void WriteStringToFile(string path, string content, bool overwrite = true, Encoding? encoding = null)
        {
            Check.NotNull(path, nameof(path));
            Check.NotNull(content, nameof(content));

            try
            {
                // 规范化文件路径
                path = Path.GetFullPath(path);

                // 设置默认编码为 UTF-8
                encoding ??= new UTF8Encoding(false);

                // 获取目录路径
                string? directory = Path.GetDirectoryName(path);
                if (!string.IsNullOrEmpty(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                // 根据 overwrite 参数决定写入方式
                if (overwrite || !File.Exists(path))
                {
                    File.WriteAllText(path, content, encoding);
                }
                else
                {
                    // 追加模式，先添加换行符
                    if (!content.StartsWith(Environment.NewLine))
                    {
                        content = Environment.NewLine + content;
                    }
                    File.AppendAllText(path, content, encoding);
                }
            }
            catch (Exception ex) when (ex is not ArgumentNullException)
            {
                throw new IOException($"写入文件 '{path}' 时发生错误: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 异步将字符串内容写入指定的文件
        /// </summary>
        /// <param name="path">文件完整路径</param>
        /// <param name="content">要写入的内容</param>
        /// <param name="overwrite">是否覆盖现有文件，默认为 true</param>
        /// <param name="encoding">文件编码，默认为 UTF-8</param>
        /// <returns>表示异步写入操作的任务</returns>
        /// <exception cref="ArgumentNullException">path 或 content 为 null 时抛出</exception>
        /// <exception cref="ArgumentException">path 为空字符串或仅包含空白字符时抛出</exception>
        /// <exception cref="PathTooLongException">指定的路径超过了系统定义的最大长度</exception>
        /// <exception cref="DirectoryNotFoundException">指定的路径无效</exception>
        /// <exception cref="IOException">写入文件时发生 IO 错误</exception>
        /// <exception cref="UnauthorizedAccessException">没有写入文件的权限</exception>
        public static async Task WriteStringToFileAsync(string path, string content, bool overwrite = true, Encoding? encoding = null)
        {
            Check.NotNull(path, nameof(path));
            Check.NotNull(content, nameof(content));

            try
            {
                // 规范化文件路径
                path = Path.GetFullPath(path);

                // 设置默认编码为 UTF-8
                encoding ??= new UTF8Encoding(false);

                // 获取目录路径
                string? directory = Path.GetDirectoryName(path);
                if (!string.IsNullOrEmpty(directory))
                {
                    Directory.CreateDirectory(directory);
                }

                // 根据 overwrite 参数决定写入方式
                if (overwrite || !File.Exists(path))
                {
                    await File.WriteAllTextAsync(path, content, encoding);
                }
                else
                {
                    // 追加模式，先添加换行符
                    if (!content.StartsWith(Environment.NewLine))
                    {
                        content = Environment.NewLine + content;
                    }
                    await File.AppendAllTextAsync(path, content, encoding);
                }
            }
            catch (Exception ex) when (ex is not ArgumentNullException)
            {
                throw new IOException($"异步写入文件 '{path}' 时发生错误: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// 如果文件存在则删除
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static bool RemoveIfExists(string filePath)
        {
            if (!File.Exists(filePath))
                return false;

            File.Delete(filePath);
            return true;
        }

        public static string? GetExtension(string fileNameWithExtension)
        {
            Check.NotNull(fileNameWithExtension, nameof(fileNameWithExtension));

            var lastDotIndex = fileNameWithExtension.LastIndexOf('.');
            if (lastDotIndex < 0)
            {
                return null;
            }

            return fileNameWithExtension[(lastDotIndex + 1)..];
        }

        public static string CreateFileNameForOss(string fileName)
        {
            return RandomHelper.GetRandomString(4, true, true, false, false) + fileName;
        }
    }
}